﻿/*************************************************************************
 *
 * Copyright (c) 2009-2015 Xuld. All rights reserved.
 * 
 * Project Url: http://work.xuld.net/circus
 * 
 * This source code is part of the Project Circus.
 * 
 * This code is licensed under The Circus License.
 * See the file License.html for the license details.
 * 
 * 
 * You must not remove this notice, or any other, from this software.
 *
 * 
 *************************************************************************/



using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace Circus.Utility {

    /// <summary>
    /// 提供用于创建、复制、删除、移动和打开文件和文件夹的静态方法。
    /// </summary>
    /// <remarks>
    /// 相对于 <see cref="File"/> 和 <see cref="Directory"/> 对象，<c>FileHelper</c> 不会因为文件或目录不存在而引发异常。相对地，<c>FileHelper</c>会创建默认的目录和返回默认的值。
    /// </remarks>
    public static class FileHelper {

        #region 文件操作准备操作

        /// <summary>
        /// 确保指定路径的文件不存在，否则对指定路径重命名。
        /// </summary>
        /// <param name="filePath">要确认的路径。</param>
        /// <returns>新的文件名。</returns>
        public static string getUniqueFileName(string filePath) {

            // 不处理空路径。
            if (filePath == null || filePath.Length == 0) {
                return "(1)";
            }
            
            if (File.Exists(filePath)) {

                // 删除文件名和扩展名部分。
                string fileName = filePath;
                string ext = String.Empty;

                for (int len = filePath.Length, j = len; j-- > 0; ) {
                    char ch = filePath[j];
                    if (ch == '.') {
                        fileName = filePath.Substring(0, j);
                        ext = filePath.Substring(j, len - j);
                        break;
                    }
                    if (ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar) {
                        break;
                    }
                }

                int i = 2;
                while (File.Exists(filePath = String.Concat(fileName, " (", i++, ')', ext)))
                    ;

            }

            return filePath;
        }

        /// <summary>
        /// 在创建一个文件前，确保该文件存储位置可以正常地保存文件。如果文件已存在则删除，如果所在文件夹不存在则创建。
        /// </summary>
        /// <param name="filePath">要保存的文件位置。</param>
        /// <param name="overwrite">覆盖的方式。</param>
        /// <returns>返回实际需要保存的文件路径。如果返回 null 表示不可创建此文件。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="filePath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="filePath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="filePath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="filePath"/> 是一个目录。- 或 -<paramref name="filePath"/> 指定一个只读文件。</exception>
        public static string prepareFilePath(string filePath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            if (File.Exists(filePath)) {
                switch (overwrite) {
                    case FileOverwrite.overwrite:
                        File.Delete(filePath);
                        return filePath;
                    case FileOverwrite.ignore:
                        return null;
                    case FileOverwrite.rename:
                        return getUniqueFileName(filePath);
                    default:
                        throw new IOException("文件 " + filePath + " 已存在");
                }
            } else {
                string dir = Path.GetDirectoryName(filePath);
                if (dir != null && dir.Length != 0) {
                    Directory.CreateDirectory(dir);
                }
                return filePath;
            }
        }

        #endregion

        #region 删除

        /// <summary>
        /// 删除指定的文件。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="path">要删除的文件的名称。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void deleteFile(string path) {
            File.Delete(path);
        }

        /// <summary>
        /// 粉碎指定的文件。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="path">要删除的文件的名称。</param>
        /// <remarks>
        /// 相对于 <see cref="deleteFile"/>, 此函数能删除一些无法正常删除的文件，但此函数效率低。
        /// </remarks>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void deleteFileForced(string path) {
            if (File.Exists(path)) {
                File.SetAttributes(path, FileAttributes.Normal);
                deleteDirectory(path);
                long size = GetFileLength(path);
                File.WriteAllBytes(path, new byte[size]);
                File.Delete(path);
            }
        }

        /// <summary>
        /// 删除指定的目录并删除该目录中的任何子目录和文件。如果指定的目录不存在，则不引发异常。
        /// </summary>
        /// <param name="path">要移除的目录的名称。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void deleteDirectory(string path) {
            if (Directory.Exists(path)) {
                Directory.Delete(path, true);
            }
        }

        /// <summary>
        /// 删除指定目录中的任何子目录和文件。如果指定的目录不存在，则创建空目录。
        /// </summary>
        /// <param name="path">要清空的目录的名称。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void cleanDirectory(string path) {
            deleteDirectory(path);
            createDirectory(path);
        }

        #endregion

        #region 复制

        /// <summary>
        /// 将现有文件复制到新文件。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于复制的文件位置。</param>
        /// <param name="destPath">复制后的文件保存位置。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>如果文件被成功复制，则返回新文件的路径， 否则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        public static string copyFile(string sourcePath, string destPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            switch (overwrite) {
                case FileOverwrite.overwrite:
                    File.Copy(sourcePath, destPath, true);
                    return destPath;
                case FileOverwrite.ignore:
                    if (File.Exists(destPath)) {
                        return destPath;
                    }
                    goto default;
                case FileOverwrite.rename:
                    destPath = getUniqueFileName(destPath);
                    goto default;
                default:
                    File.Copy(sourcePath, destPath);
                    return destPath;
            }
        }

        /// <summary>
        /// 将现有目录复制到新目录。如果指定的目录不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于复制的目录位置。</param>
        /// <param name="destPath">复制后的目录保存位置。</param>
        /// <param name="overwrite">指定当目标目录已经存在时，应该采取的行为。默认为合并。</param>
        /// <returns>如果目录被成功复制，则返回新目录的路径， 否则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        public static void copyDirectory(string sourcePath, string destPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            if (Directory.Exists(sourcePath)) {
                copyDirectoryInternal(sourcePath, destPath, overwrite);
            }
        }

        /// <summary>
        /// 将现有目录复制到新目录。
        /// </summary>
        /// <param name="sourcePath">用于复制的目录位置。</param>
        /// <param name="destPath">复制后的目录保存位置。</param>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        static void copyDirectoryInternal(string sourcePath, string destPath, FileOverwrite overwrite) {

            // 创建目标文件夹。
            Directory.CreateDirectory(destPath);

            // 复制子目录。
            foreach (string child in Directory.GetDirectories(sourcePath)) {
                copyDirectoryInternal(child, PathHelper.changeDirectory(child, destPath), overwrite);
            }

            // 复制所有文件。
            foreach (string file in Directory.GetFiles(sourcePath)) {
                copyFile(file, PathHelper.changeDirectory(file, destPath), overwrite);
            }

        }

        /// <summary>
        /// 将现有文件复制到指定的文件夹。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于复制的文件位置。</param>
        /// <param name="destDirectoryPath">复制后的文件保存位置。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>返回新文件的位置。如果复制失败，则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个目录。- 或 -<paramref name="destDirectoryPath"/> 指定一个只读文件。</exception>
        public static string copyFileTo(string sourcePath, string destDirectoryPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            return copyFile(sourcePath, PathHelper.changeDirectory(sourcePath, destDirectoryPath), overwrite);
        }

        /// <summary>
        /// 将现有目录复制到新目录。如果指定的目录不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于复制的目录位置。</param>
        /// <param name="destDirectoryPath">复制后的目录保存位置。</param>
        /// <param name="overwrite">指定当目标目录已经存在时，应该采取的行为。默认为合并。</param>
        /// <returns>返回新目录的位置。如果复制失败，则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个目录。- 或 -<paramref name="destDirectoryPath"/> 指定一个只读文件。</exception>
        public static void copyDirectoryTo(string sourcePath, string destDirectoryPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            copyDirectory(sourcePath, PathHelper.changeDirectory(sourcePath, destDirectoryPath), overwrite);
        }

        #endregion

        #region 新建

        /// <summary>
        /// 在指定路径中创建文件。
        /// </summary>
        /// <param name="path">要创建的文件的路径及名称。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>一个 <see cref="System.IO.FileStream"/>，它提供对 <paramref name="path"/> 中指定的文件的读/写访问。如果无法创建新文件，则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static FileStream createFile(string path, FileOverwrite overwrite = FileOverwrite.overwrite) {
            var p = FileHelper.prepareFilePath(path, overwrite);
            return p == null ? File.OpenRead(path) : File.Create(p);
        }

        /// <summary>
        /// 按 <paramref name="path"/> 的指定创建所有目录和子目录。
        /// </summary>
        /// <param name="path">要创建的目录路径。</param>
        /// <param name="overwrite">指定当目标目录已经存在时，应该采取的行为。默认为合并。</param>
        /// <returns>返回创建的目录。如果创建失败，则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static DirectoryInfo createDirectory(string path) {
            return Directory.CreateDirectory(path);
        }

        #endregion

        #region 移动

        /// <summary>
        /// 将指定文件移到新位置，并提供指定新文件名的选项。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">要移动的文件的名称。</param>
        /// <param name="destPath">文件的新路径。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>如果文件被成功剪切，则返回新文件的路径， 否则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        public static string moveFile(string sourcePath, string destPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            var p = FileHelper.prepareFilePath(destPath, overwrite);
            if (p != null) {
                File.Move(sourcePath, p);
                destPath = p;
            }
            return destPath;
        }

        /// <summary>
        /// 将文件或目录及其内容移到新位置。如果指定的目录不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">要移动的文件或目录的路径。</param>
        /// <param name="destPath">指向 <paramref name="sourcePath"/> 的新位置的路径。如果 <paramref name="sourcePath"/> 是一个文件，则 <paramref name="destPath"/> 也必须是一个文件名。</param>
        /// <param name="overwrite">指定当目标目录已经存在时，应该采取的行为。默认为合并。</param>
        /// <returns>如果目录被成功剪切，则返回新目录的路径， 否则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        public static string moveDirectory(string sourcePath, string destPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            if (Directory.Exists(sourcePath)) {
                Directory.Move(sourcePath, destPath);
                return destPath;
            }
            return null;
        }

        /// <summary>
        /// 将现有文件移动到指定的文件夹。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于移动的文件位置。</param>
        /// <param name="destDirectoryPath">移动后的文件保存位置。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>返回新文件的位置。如果移动失败，则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个目录。- 或 -<paramref name="destDirectoryPath"/> 指定一个只读文件。</exception>
        public static string moveFileTo(string sourcePath, string destDirectoryPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            return moveFile(sourcePath, PathHelper.changeDirectory(sourcePath, destDirectoryPath), overwrite);
        }

        /// <summary>
        /// 将现有目录移动到新目录。如果指定的目录不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">用于移动的目录位置。</param>
        /// <param name="destDirectoryPath">移动后的目录保存位置。</param>
        /// <param name="overwrite">指定当目标目录已经存在时，应该采取的行为。默认为合并。</param>
        /// <returns>返回新目录的位置。如果移动失败，则返回 null。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destDirectoryPath"/> 是一个目录。- 或 -<paramref name="destDirectoryPath"/> 指定一个只读文件。</exception>
        public static string moveDirectoryTo(string sourcePath, string destDirectoryPath, FileOverwrite overwrite = FileOverwrite.overwrite) {
            return moveDirectory(sourcePath, PathHelper.changeDirectory(sourcePath, destDirectoryPath), overwrite);
        }

        /// <summary>
        /// 用其他文件的内容替换指定文件的内容，删除原始文件，并创建被替换文件的备份。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="sourcePath">替换由 <paramref name="destPath"/> 指定的文件的文件名。</param>
        /// <param name="destPath">替换文件的名称。</param>
        /// <param name="bakFileName">备份文件的名称。默认为原文件名尾缀 .bak 的文件名。</param>
        /// <exception cref="System.ArgumentException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="sourcePath"/> 或 <paramref name="destPath"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="sourcePath"/> 或 <paramref name="destPath"/> 是一个目录。- 或 -<paramref name="destPath"/> 指定一个只读文件。</exception>
        public static void replace(string sourcePath, string destPath, string bakFileName = null) {
            if (File.Exists(sourcePath)) {
                File.Replace(sourcePath, destPath, PathHelper.changeFileName(sourcePath, bakFileName ?? (Path.GetFileName(sourcePath) + ".bak")), true);
            }
        }

        #endregion

        #region 属性

        /// <summary>
        /// 添加指定路径上文件的指定的 <see cref="System.IO.FileAttributes"/>。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="path">该文件的路径。</param>
        /// <param name="fileAttributes">所需的 <see cref="System.IO.FileAttributes"/>，例如 Hidden、ReadOnly、Normal 和 Archive。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void addAttributes(string path, FileAttributes fileAttributes) {
            File.SetAttributes(path, fileAttributes | File.GetAttributes(path));
        }

        /// <summary>
        /// 删除指定路径上文件的指定的 <see cref="System.IO.FileAttributes"/>。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="path">该文件的路径。</param>
        /// <param name="fileAttributes">所需的 <see cref="System.IO.FileAttributes"/>，例如 Hidden、ReadOnly、Normal 和 Archive。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void removeAttributes(string path, FileAttributes fileAttributes) {
            if (File.Exists(path)) {
                File.SetAttributes(path, File.GetAttributes(path) & ~fileAttributes);
            }
        }

        /// <summary>
        /// 设置指定路径上文件的指定的 <see cref="System.IO.FileAttributes"/>。如果指定的文件不存在，则不引发异常。
        /// </summary>
        /// <param name="path">该文件的路径。</param>
        /// <param name="fileAttributes">所需的 <see cref="System.IO.FileAttributes"/>，例如 Hidden、ReadOnly、Normal 和 Archive。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void setAttributes(string path, FileAttributes fileAttributes = FileAttributes.Normal) {
            File.SetAttributes(path, fileAttributes);
        }

        #endregion

        #region 检查

        /// <summary>
        /// 确定文件或目录是否存在。
        /// </summary>
        /// <param name="path">要检查的文件或目录。</param>
        /// <returns>如果调用方具有要求的权限并且 path 包含现有文件或目录的名称，则为 true；否则为 false。如果 path 为 null、无效路径或零长度字符串，则此方法也将返回 false。如果调用方不具有读取指定文件或目录所需的足够权限，则不引发异常并且该方法返回 false，这与 path 是否存在无关。</returns>
        public static bool exists(string path) {
            return File.Exists(path) || Directory.Exists(path);
        }

        /// <summary>
        /// 确定文件是否存在。
        /// </summary>
        /// <param name="path">要检查的文件。</param>
        /// <returns>如果调用方具有要求的权限并且 path 包含现有文件的名称，则为 true；否则为 false。如果 path 为 null、无效路径或零长度字符串，则此方法也将返回 false。如果调用方不具有读取指定文件所需的足够权限，则不引发异常并且该方法返回 false，这与 path 是否存在无关。</returns>
        public static bool existsFile(string path) {
            return File.Exists(path);
        }

        /// <summary>
        /// 确定目录是否存在。
        /// </summary>
        /// <param name="path">要检查的目录。</param>
        /// <returns>如果调用方具有要求的权限并且 path 包含现有目录的名称，则为 true；否则为 false。如果 path 为 null、无效路径或零长度字符串，则此方法也将返回 false。如果调用方不具有读取指定目录所需的足够权限，则不引发异常并且该方法返回 false，这与 path 是否存在无关。</returns>
        public static bool existsDirectory(string path) {
            return Directory.Exists(path);
        }

        /// <summary>
        /// 检查目前是否具有指定文件的修改权限。
        /// </summary>
        /// <returns>如果可以修改文件，则返回 true, 否则返回 false。如果指定的文件不存在，则返回 false 。</returns>
        public static bool IsFileWritable(string path) {
            if (!File.Exists(path))
                return false;
            try {
                File.OpenWrite(path).Close();
            } catch {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 检查目前是否具有指定目录的修改权限。
        /// </summary>
        /// <returns>如果可以修改目录，则返回 true, 否则返回 false。如果指定的目录不存在，则返回 false 。</returns>
        public static bool IsDirectoryWritable(string path) {
            if (!Directory.Exists(path))
                return false;
            string newFile = PathHelper.CombinePath(path, "__test.tmp");

            try {
                using (FileStream fs = createFile(newFile, FileOverwrite.rename)) {
                    newFile = fs.Name;
                }
                deleteFile(newFile);
            } catch {
                return false;
            }
            return true;
        }

        #endregion

        #region 子文件和目录

        static string[] SelectMatchedEntry(string[] entries, Predicate<string> predicate) {
            int i = 0;
            for (int j = 0; j < entries.Length; j++) {
                if (predicate(entries[i])) {
                    entries[i++] = entries[j];
                }
            }

            string[] r = new string[i];
            Array.Copy(entries, r, i);
            return r;
        }

        static string[] ToArray(SortedList<string, string> result) {
            string[] r = new string[result.Count];
            int i = 0;
            foreach (var s in result) {
                r[i++] = s.Key;
            }

            return r;
        }

        /// <summary>
        /// 返回指定目录中文件的名称，使用某个值确定是否在子目录中搜索。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="option"><see cref="System.IO.SearchOption"/> 值之一，指定搜索操作应包括所有子目录还是仅包括当前目录。</param>
        /// <returns>一个 String 数组，它包含指定目录中与指定搜索模式匹配的文件的名称。文件名包含完整路径。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFiles(string path, SearchOption option = SearchOption.AllDirectories) {
            if (!Directory.Exists(path))
                return new string[0] { };
            return Directory.GetFiles(path, "*", option);
        }

        /// <summary>
        /// 返回指定目录中文件的名称，该目录与指定正则表达式匹配并使用某个值确定是否在子目录中搜索。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="searchPatterns">一个 <see cref="Regex"/>, 用于测试指定的文件名是否符合要求。</param>
        /// <param name="option"><see cref="System.IO.SearchOption"/> 值之一，指定搜索操作应包括所有子目录还是仅包括当前目录。</param>
        /// <returns>一个 String 数组，它包含指定目录中与指定搜索模式匹配的文件的名称。文件名包含完整路径。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFiles(string path, Regex searchPatterns, SearchOption option = SearchOption.AllDirectories) {
            if (!Directory.Exists(path))
                return new string[0] { };
            return SelectMatchedEntry(Directory.GetFiles(path, "*", option), path2 => searchPatterns.IsMatch(Path.GetFileName(path2)));
        }

        /// <summary>
        /// 返回指定目录中文件的名称，该目录与指定搜索模式匹配并使用某个值确定是否在子目录中搜索。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="searchPatterns">要与 <paramref name="path"/> 中的文件名匹配的搜索字符串。此参数不能以两个句点（“..”）结束，不能在 System.IO.Path.DirectorySeparatorChar 或 <see cref="System.IO.Path.AltDirectorySeparatorChar"/> 的前面包含两个句点（“..”），也不能包含 <see cref="System.IO.Path.InvalidPathChars"/> 中的任何字符。多个文件名直接用;隔开。如 *.jpg;*.bmp 。</param>
        /// <param name="option"><see cref="System.IO.SearchOption"/> 值之一，指定搜索操作应包括所有子目录还是仅包括当前目录。</param>
        /// <returns>一个 String 数组，它包含指定目录中与指定搜索模式匹配的文件的名称。文件名包含完整路径。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFiles(string path, string searchPatterns, SearchOption option = SearchOption.AllDirectories) {
            if (!Directory.Exists(path))
                return new string[0] { };
            string[] searchPattern = Str.SplitAndTrim(searchPatterns, ';');
            if (searchPattern.Length == 1) {
                return Directory.GetFiles(path, searchPattern[0], option);
            }

            SortedList<string, string> result = new SortedList<string, string>();
            foreach (string s in Directory.GetFiles(path, "*", option)) {
                result[s] = s;
            }

            return ToArray(result);
        }

        /// <summary>
        /// 返回指定目录中文件的名称，该目录与指定搜索模式匹配并使用某个值确定是否在子目录中搜索。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="option"><see cref="System.IO.SearchOption"/> 值之一，指定搜索操作应包括所有子目录还是仅包括当前目录。</param>
        /// <returns>与搜索模式匹配的目录的 String 数组。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetDirectories(string path, SearchOption option = SearchOption.TopDirectoryOnly) {
            if (!Directory.Exists(path))
                return new string[0] { };
            return Directory.GetDirectories(path, "*", option);
        }

        /// <summary>
        /// 返回指定目录中文件的名称，该目录与指定搜索模式匹配并使用某个值确定是否在子目录中搜索。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="searchPatterns">要与 <paramref name="path"/> 中的文件名匹配的搜索字符串。此参数不能以两个句点（“..”）结束，不能在 System.IO.Path.DirectorySeparatorChar 或 <see cref="System.IO.Path.AltDirectorySeparatorChar"/> 的前面包含两个句点（“..”），也不能包含 <see cref="System.IO.Path.InvalidPathChars"/> 中的任何字符。多个文件名直接用;隔开。如 *.jpg;*.bmp 。</param>
        /// <param name="option"><see cref="System.IO.SearchOption"/> 值之一，指定搜索操作应包括所有子目录还是仅包括当前目录。</param>
        /// <returns>与搜索模式匹配的目录的 String 数组。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetDirectories(string path, string searchPatterns, SearchOption option = SearchOption.TopDirectoryOnly) {
            if (!Directory.Exists(path))
                return new string[0] { };
            string[] searchPattern = Str.SplitAndTrim(searchPatterns, ';');
            if (searchPattern.Length == 1) {
                return Directory.GetDirectories(path, searchPattern[0], option);
            }

            SortedList<string, string> result = new SortedList<string, string>();
            foreach (string s in Directory.GetDirectories(path, "*", option)) {
                result[s] = s;
            }

            return ToArray(result);
        }

        /// <summary>
        /// 返回指定目录中所有文件和子目录的名称。
        /// </summary>
        /// <param name="path">为其返回文件名和子目录名的目录。</param>
        /// <returns>一个 String 数组，它包含指定目录中文件系统项的名称。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFileSystemEntries(string path) {
            if (!Directory.Exists(path))
                return new string[0] { };
            return Directory.GetFileSystemEntries(path, "*");
        }

        /// <summary>
        /// 返回与指定正则表达式匹配的文件系统项的数组。
        /// </summary>
        /// <param name="path">要搜索的目录。</param>
        /// <param name="searchPatterns">一个 <see cref="Regex"/>, 用于测试指定的文件名是否符合要求。</param>
        /// <returns>一个 String 数组，它包含指定目录中与指定搜索模式匹配的文件的名称。文件名包含完整路径。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFileSystemEntries(string path, Regex searchPatterns) {
            if (!Directory.Exists(path))
                return new string[0] { };
            return SelectMatchedEntry(Directory.GetFileSystemEntries(path, "*"), path2 => searchPatterns.IsMatch(Path.GetFileName(path2)));
        }

        /// <summary>
        /// 返回与指定搜索条件匹配的文件系统项的数组。
        /// </summary>
        /// <param name="path">要搜索的路径。</param>
        /// <param name="searchPatterns">要与 <paramref name="path"/> 中的文件名匹配的搜索字符串。此参数不能以两个句点（“..”）结束，不能在 System.IO.Path.DirectorySeparatorChar 或 <see cref="System.IO.Path.AltDirectorySeparatorChar"/> 的前面包含两个句点（“..”），也不能包含 <see cref="System.IO.Path.InvalidPathChars"/> 中的任何字符。多个文件名直接用;隔开。如 *.jpg;*.bmp 。</param>
        /// <returns>一个 String 数组，它包含与搜索条件匹配的文件系统项。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string[] GetFileSystemEntries(string path, string searchPatterns) {
            if (!Directory.Exists(path))
                return new string[0] { };
            string[] searchPattern = Str.SplitAndTrim(searchPatterns, ';');
            if (searchPattern.Length == 1) {
                return Directory.GetFileSystemEntries(path, searchPattern[0]);
            }

            SortedList<string, string> result = new SortedList<string, string>();
            foreach (string s in Directory.GetFileSystemEntries(path, "*")) {
                result[s] = s;
            }

            return ToArray(result);
        }

        #endregion

        #region 信息

        /// <summary>
        /// 获取指定文件的长度。
        /// </summary>
        /// <param name="path">要获取文件长度的文件位置。</param>
        /// <returns>返回文件的大小。如果文件不存在，则返回 -1。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static long GetFileLength(string path) {
            FileInfo fi = new FileInfo(path);
            if (fi.Exists)
                return fi.Length;
            return -1L;
        }

        /// <summary>
        /// 确定一个目录是否包含匹配指定模式的子目录或文件。
        /// </summary>
        /// <param name="path">要确定的目录位置。</param>
        /// <param name="searchPatterns">要与 <paramref name="path"/> 中的文件名匹配的搜索字符串。此参数不能以两个句点（“..”）结束，不能在 System.IO.Path.DirectorySeparatorChar 或 <see cref="System.IO.Path.AltDirectorySeparatorChar"/> 的前面包含两个句点（“..”），也不能包含 <see cref="System.IO.Path.InvalidPathChars"/> 中的任何字符。多个文件名直接用;隔开。如 *.jpg;*.bmp 。</param>
        /// <returns>如果该目录不包含任何子目录或文件，则返回 true，否则返回 false。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.Security.SecurityException">调用方没有所要求的权限。</exception>
        public static bool ContainsFileSystemEntry(string path, string searchPatterns = "*") {
            DirectoryInfo d = new DirectoryInfo(path);
            if (d.Exists) {
                return d.GetFileSystemInfos(searchPatterns).Length > 0;

            }

            return false;
        }

        #endregion

        #region 编码

        /// <summary>
        /// 给定文件的路径，读取文件的二进制数据，判断文件的编码类型。
        /// </summary>
        /// <param name="path">要判断编码的文件路径。</param>
        /// <returns>一个 <see cref="Encoding"/> 对象，表示指定文件的编码。</returns>
        public static Encoding getEncoding(string path) {
            if (!File.Exists(path))
                return Encoding.Default;
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                return getEncoding(fs);
        }

        /// <summary>
        /// 通过给定的文件流，判断文件的编码类型。
        /// </summary>
        /// <param name="seekableStream">要判断编码的文件流。</param>
        /// <returns>一个 <see cref="Encoding"/> 对象，表示指定文件流的编码。</returns>
        /// <exception cref="System.NotSupportedException"><paramref name="seekableStream"/> 不支持 Seek 。</exception>
        public static Encoding getEncoding(Stream seekableStream) {
            //byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
            //byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
            //byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM
            Encoding reVal = Encoding.Default;
            long position = seekableStream.Position;
            seekableStream.Position = 0;  //  清空。
            BinaryReader r = new BinaryReader(seekableStream, reVal);
            int i = Math.Min((int)seekableStream.Length, 1024 * 1024);
            if (i >= 2) {
                i = 4;
                byte[] ss = r.ReadBytes(i);
                if (CorePlus.IO.StreamHelper.IsUTF8Bytes(ss)) {
                    reVal = Encoding.UTF8;
                } else if (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF) {
                    reVal = Encoding.UTF8;
                } else if (ss[0] == 0xFE && ss[1] == 0xFF /* && ss[2] == 0x00  */  ) {
                    reVal = Encoding.BigEndianUnicode;
                } else if (ss[0] == 0xFF && ss[1] == 0xFE /* && ss[2] == 0x41 */) {
                    reVal = Encoding.Unicode;
                }
            }

            seekableStream.Position = position;
            return reVal;

        }

        #endregion

        #region 临时文件

        /// <summary>
        /// 创建磁盘上唯一命名的零字节的临时文件并返回该用于输出到该文件的 <see cref="FileStream"/>。
        /// </summary>
        /// <returns>一个 <see cref="FileStream"/>， 用于写入该临时文件。</returns>
        public static FileStream getTempFile() {
            return File.OpenWrite(Path.GetTempFileName());
        }

        /// <summary>
        /// 在指定的目录创建磁盘上唯一命名的零字节的临时文件并返回该用于输出到该文件的 <see cref="FileStream"/>。
        /// </summary>
        /// <param name="path">临时文件所在的父目录。</param>
        /// <param name="extension">期望使用的扩展名(含点)。</param>
        /// <returns>一个 <see cref="FileStream"/>， 用于写入该临时文件。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static FileStream getTempFile(string path, string extension = ".tmp") {
            return File.OpenWrite(PathHelper.GetTempFile(path, extension));
        }

        #endregion

        #region 文件内容操作

        /// <summary>
        /// 创建一个新文件，在其中写入指定的字符串，然后关闭文件。
        /// </summary>
        /// <param name="path">要写入的文件。</param>
        /// <param name="contents">要写入的文件的字符串。</param>
        /// <param name="encoding">一个 <see cref="System.Text.Encoding"/> 对象，表示应用于字符串的编码。</param>
        /// <param name="overwrite">指定当目标文件已经存在时，应该采取的行为。默认为强制覆盖。</param>
        /// <returns>如果写入成功则返回新文件名，否则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string WriteAllText(string path, string contents, Encoding encoding = null, FileOverwrite overwrite = FileOverwrite.overwrite) {
            FileStream fs = createFile(path, overwrite);
            if (fs != null) {
                string r = fs.Name;
                StreamWriter sw = new StreamWriter(fs, encoding ?? Encoding.Default);

                try {
                    sw.Write(contents);
                } finally {
                    sw.Dispose();
                }

                return r;
            }

            return null;
        }

        /// <summary>
        /// 将指定的字符串追加到文件中，如果文件还不存在则创建该文件。
        /// </summary>
        /// <param name="path">要将指定的字符串追加到的文件。</param>
        /// <param name="contents">要追加到文件中的字符串。</param>
        /// <param name="encoding">要使用的字符编码。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void AppendAllText(string path, string contents, Encoding encoding = null) {
            File.AppendAllText(path, contents, encoding ?? Encoding.Default);
        }

        /// <summary>
        /// 转换文件的编码。
        /// </summary>
        /// <param name="path">要转换编码的文件。</param>
        /// <param name="encoding">转换后的新编码。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void ChangeEncoding(string path, System.Text.Encoding encoding) {
            ChangeEncoding(path, getEncoding(path), encoding);
        }

        /// <summary>
        /// 转换文件的编码。
        /// </summary>
        /// <param name="path">要转换编码的文件。</param>
        /// <param name="srcEncoding">转换前的编码。</param>
        /// <param name="destEncoding">转换后的新编码。</param>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static void ChangeEncoding(string path, System.Text.Encoding srcEncoding, System.Text.Encoding destEncoding) {
            if (srcEncoding != destEncoding && File.Exists(path)) {
                File.WriteAllText(path, File.ReadAllText(path, srcEncoding), destEncoding);
            }
        }

        /// <summary>
        /// 打开一个文件，使用指定的编码读取文件的所有行，然后关闭该文件。
        /// </summary>
        /// <param name="path">要打开以进行读取的文件。</param>
        /// <param name="encoding">应用到文件内容的编码。</param>
        /// <returns>包含文件所有行的字符串。如果文件不存在，则返回 null 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static string ReadAllText(string path, Encoding encoding = null) {
            if (File.Exists(path))
                return File.ReadAllText(path, encoding ?? getEncoding(path));

            return null;
        }

        /// <summary>
        /// 打开现有文件以进行写入。
        /// </summary>
        /// <param name="path">要打开以进行写入的文件。</param>
        /// <returns>具有 <see cref="System.IO.FileAccess.Write"/> 访问权限的指定路径上的非共享 <see cref="System.IO.FileStream"/> 对象。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static FileStream OpenWrite(string path) {
            PathHelper.PrepareDirectoryPath(path);
            return new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
        }

        /// <summary>
        /// 打开现有文件以进行读取。如果文件不存在，则返回 <see cref="P:Stream.Null"/> 。
        /// </summary>
        /// <param name="path">要打开以进行读取的文件。</param>
        /// <returns>指定路径上的只读 <see cref="Stream"/>, 如果文件不存在，则返回 <see cref="P:Stream.Null"/> 。</returns>
        /// <exception cref="System.ArgumentException"><paramref name="path"/> 是一个零长度字符串，仅包含空白或者包含一个或多个由 <see cref="System.IO.Path.InvalidPathChars"/> 定义的无效字符。</exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="path"/> 为 null。</exception>
        /// <exception cref="System.IO.DirectoryNotFoundException">指定的路径无效（例如，它位于未映射的驱动器上）。</exception>
        /// <exception cref="System.IO.IOException">指定的文件正在使用中。</exception>
        /// <exception cref="System.NotSupportedException"><paramref name="path"/> 的格式无效。</exception>
        /// <exception cref="System.IO.PathTooLongException">指定的路径、文件名或者两者都超出了系统定义的最大长度。例如，在基于 Windows 的平台上，路径必须小于 248 个字符，文件名必须小于 260 个字符。</exception>
        /// <exception cref="System.UnauthorizedAccessException">调用方没有所要求的权限。- 或 -<paramref name="path"/> 是一个目录。- 或 -<paramref name="path"/> 指定一个只读文件。</exception>
        public static Stream OpenRead(string path) {
            path = Path.GetFullPath(path);
            if (File.Exists(path))
                return File.OpenRead(path);
            return Stream.Null;
        }

        #endregion

    }

    /// <summary>
    /// 指示文件或目录强制覆盖的行为。
    /// </summary>
    public enum FileOverwrite {

        /// <summary>
        /// 覆盖已存在的文件。
        /// </summary>
        overwrite,

        /// <summary>
        /// 忽略当前操作。
        /// </summary>
        ignore,

        /// <summary>
        /// 自动重命名要复制的文件。
        /// </summary>
        rename,

        /// <summary>
        /// 引发一个 <see cref="System.IO.IOException"/> 异常。
        /// </summary>
        throwException,

    }
}
